package com.example.function.integration.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.example.function.integration.constant.CommonConstant;
import com.example.function.integration.entity.HuanengCreditDataEntity;
import com.example.function.integration.exception.BizException;
import com.example.function.integration.service.AbstractDataExportService;
import com.example.function.integration.service.CreditApplyDataExportService;
import com.example.function.integration.utils.CryptoUtils;
import com.example.function.integration.utils.ExcelUtils;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Future;

import static com.example.function.integration.constant.CommonConstant.XLSX;

/**
 * @description：授信申请数据导出服务接口实现类
 * @className：CreditApplyDataExportService
 * @author：ext.fengcheng
 * @date：2023/9/7 10:26
 */
@Service
public class CreditApplyDataExportServiceImpl extends AbstractDataExportService implements CreditApplyDataExportService {

    /**
     * @Description：导出授信申请数据
     * @Author： ext.fengcheng
     * @Date：2023/9/7 10:26
     * @Param： [tenantId, queryNum]
     * @Return： boolean
     */
    @Override
    public boolean creditApplyDataExport(String tenantId, Long queryNum, String fileName, Long sheetNum, Integer sheetPageNum, HttpServletResponse response) {
        String remark = "CreditApplyDataExportServiceImpl.creditApplyDataExport.";
        logger.info("{}开始处理授信数据查询、组装、导出等逻辑", remark);
        CommonConstant.FILE_NAME = fileName;
        Long startId = 0L;
        if (ObjectUtils.isEmpty(queryNum)) {
            queryNum = QUERY_PAGE_SIZE;
        }
        if (ObjectUtils.isEmpty(sheetNum)) {
            sheetNum = SHEET_NUM;
        }
        if (ObjectUtils.isEmpty(sheetPageNum)) {
            sheetPageNum = SHEET_PAGE_NUM;
        }
        int index = 1;
        Map<String, List<List<Object>>> allSheetMap = new ConcurrentHashMap<>();
        // 存放每一个sheet页的数据集合
        List<List<Object>> sheetPageDataList = new ArrayList<>();
        sheetPageDataList.add(sheetHead);
        try {
            while (true) {
                List<HuanengCreditDataEntity> dataEntityList = crlCreditApplyRecordExtendMapper.selectCreditApplyData(tenantId, startId, queryNum);
                if (CollectionUtils.isEmpty(dataEntityList)) {
                    String key = "第" + index + "批授信数据";
                    allSheetMap.put(key, sheetPageDataList);
                    logger.info("{}授信数据查询、组装完成，开始进行授信数据导出，最后一批数据，总数：{}", remark, sheetPageDataList.size());
                    ExcelUtils.exportManySheet(fileName + XLSX, false, null, allSheetMap, response);
                    logger.info("{}授信数据导出，执行完成", remark);
                    break;
                }
                //  下次查询记录ID起始值
                startId = dataEntityList.get(dataEntityList.size() - 1).getSerialNumber();
                bulidCreditApplyDataExportObj(dataEntityList, sheetPageDataList);
                // sheetPageDataList.size() - 1 因为包含了抬头，所以需要减一
                int sheetSize = sheetPageDataList.size() - 1;
                if (sheetSize >= sheetNum) {
                    String key = "第" + index + "批授信数据";
                    // 如果当前sheet页的数据大于100万，则拆分多余的数据加入新的sheet页
                    List<List<Object>> dyList = Lists.newArrayList();
                    if (sheetSize > sheetNum) {
                        int toIndex = (int) (sheetNum + 1);
                        allSheetMap.put(key, sheetPageDataList.subList(0, toIndex));
                        dyList = sheetPageDataList.subList(toIndex, sheetPageDataList.size());
                    } else {
                        allSheetMap.put(key, sheetPageDataList);
                    }
                    sheetPageDataList = new ArrayList<>();
                    sheetPageDataList.add(sheetHead);
                    if (!dyList.isEmpty()) {
                        sheetPageDataList.addAll(dyList);
                    }
                    index++;
                    // 每个元素的value存放100万数据，存满指定sheet页的数据，便开始导出
                    if (allSheetMap.size() == sheetPageNum) {
                        logger.info("{}授信数据查询、组装完成，开始进行授信数据导出", remark);
                        ExcelUtils.exportManySheet(fileName + XLSX, false, null, allSheetMap, response);
                        logger.info("{}授信数据导出，执行完成", remark);
                        allSheetMap = new ConcurrentHashMap<>();
                    }
                }
            }
        } catch (BizException e) {
            logger.error("{}导出文件数据发生异常，异常信息", remark, e);
            throw new BizException("导出文件数据发生异常");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return true;
    }

    /**
     * @Description：使用多线程构建导出的数据集合
     * @Author： ext.fengcheng
     * @Date：2023/9/7 11:44
     * @Param： [dataEntityList, sheetPageDataList]
     * @Return： void
     */
    private void bulidCreditApplyDataExportObj(List<HuanengCreditDataEntity> dataEntityList, List<List<Object>> sheetPageDataList) {
        CopyOnWriteArrayList<List<Object>> safeList = new CopyOnWriteArrayList<>();
        try {
            List<HuanengCreditDataEntity> entityList = Lists.newArrayList();
            for (int i = 0; i < dataEntityList.size(); i++) {
                entityList.add(dataEntityList.get(i));
                if (entityList.size() == 20000) {
                    logger.info("开启第【" + (i + 1) + "】个线程");
                    getFuture(entityList, safeList);
                    entityList = Lists.newArrayList();
                }
                if (i == dataEntityList.size() - 1 && !entityList.isEmpty()) {
                    logger.info("开启第【" + (i + 1) + "】个线程");
                    getFuture(entityList, safeList);
                    entityList = Lists.newArrayList();
                }
            }
            sheetPageDataList.addAll(safeList);
        } catch (Exception e) {
            logger.error("多线程处理数据转换发生异常，sheetPageDataList:{}", sheetPageDataList.size(), e);
        }
    }

    private void getFuture(List<HuanengCreditDataEntity> dataEntityList, CopyOnWriteArrayList<List<Object>> safeList) {
        List<Future<Boolean>> futures = new ArrayList<>();
        Future<Boolean> future = executor.submit(() -> {
            for (HuanengCreditDataEntity dataEntity : dataEntityList) {
                List<Object> dataVOList = Lists.newArrayList();
                dataVOList.add(dataEntity.getSerialNumber());                                                       // 序号
                dataVOList.add(dataEntity.getCreditApplyNo());                                                      // 申请流水号
                dataVOList.add(dataEntity.getOutsideCreditNo());                                                    // 外部申请流水号
                dataVOList.add(dataEntity.getCustomerCode());                                                       //客户ID
                dataVOList.add(CryptoUtils.decryptMode(dataEntity.getCustomerName()));                              // 客户姓名
                dataVOList.add(CryptoUtils.decryptMode(dataEntity.getCustomerCertNo()));                            // 客户身份证号
                dataVOList.add(dataEntity.getApplyTime());                                                          // 申请时间
                dataVOList.add(dataEntity.getProductCode());                                                        // 产品名称
                dataVOList.add(dataEntity.getCreditQuota());                                                        // 授信额度
                dataVOList.add(dataEntity.getFixedPrice());                                                         // 定价
                dataVOList.add(dataEntity.getCreditApplyStatus());                                                  // 状态
                JSONObject jsonApproveRetContent = JSONObject.parseObject(dataEntity.getApproveRetContent());
                JSONObject retResultData = jsonApproveRetContent == null ? null : JSONObject.parseObject(jsonApproveRetContent.getString("resultData"));
                dataVOList.add(retResultData == null ? "" : retResultData.getString("blackFlag"));                  // v是否黑名单

                JSONObject jsonApproveReqContent = JSONObject.parseObject(dataEntity.getApproveReqContent());
                JSONObject reqResultData = jsonApproveReqContent == null ? null : JSONObject.parseObject(jsonApproveReqContent.getString("mapData"));
                dataVOList.add(reqResultData == null ? "" : reqResultData.getString("installmentCount180"));        // 近180天（非免息）分期消费笔数
                dataVOList.add(reqResultData == null ? "" : reqResultData.getString("onlineAmountMax"));            // 近1年单笔最高消费金额
                dataVOList.add(reqResultData == null ? "" : reqResultData.getString("creditUsageAmount180"));       // 近180天信用消费金额
                dataVOList.add(reqResultData == null ? "" : reqResultData.getString("creditUsageCount180"));        // 近180天信用消费笔数
                dataVOList.add(reqResultData == null ? "" : reqResultData.getString("incomeLevel"));                // 收入等级
                dataVOList.add(reqResultData == null ? "" : reqResultData.getString("mobileStability"));            // 常用手机稳定性
                dataVOList.add(reqResultData == null ? "" : reqResultData.getString("addressStability"));           // 常用地址稳定性
                dataVOList.add(reqResultData == null ? "" : reqResultData.getString("carLevel"));                   // 有车指数等级
                dataVOList.add(reqResultData == null ? "" : reqResultData.getString("houseLevel"));                 // 有房指数等级
                dataVOList.add(reqResultData == null ? "" : reqResultData.getString("fraudScore"));                 // 欺诈评分
                dataVOList.add(reqResultData == null ? "" : reqResultData.getString("telCredibility"));             // 手机号使用频繁度
                dataVOList.add(reqResultData == null ? "" : reqResultData.getString("telUsedExist"));               // 手机号是否使用过
                dataVOList.add(reqResultData == null ? "" : reqResultData.getString("btPerformance"));              // 履约历史
                dataVOList.add(reqResultData == null ? "" : reqResultData.getString("btLevel"));                    // 小白信用等级
                dataVOList.add(reqResultData == null ? "" : reqResultData.getString("btScore"));                    // 小白信用评分
                dataVOList.add("");                                                                                 // 其他……
                safeList.add(dataVOList);
            }
            return true;
        });
        futures.add(future);
        //等待线程处理完成
        for (Future<Boolean> f : futures) {
            try {
                Boolean result = f.get();
                if (!result) {
                    logger.error("多线程构建导出的数据集合处理失败");
                }
            } catch (Exception e) {
                logger.error("等待任务执行结果发生异常", e);
            }
        }
        logger.info("safeList.size:{}", safeList.size());
    }
}
